package cn.shujuhai.common.aop;


import cn.dev33.satoken.stp.StpUtil;
import cn.shujuhai.common.domain.SysOperationLog;
import cn.shujuhai.common.service.SysOperationLogService;
import jakarta.servlet.http.HttpServletRequest;
import lombok.RequiredArgsConstructor;
import org.aspectj.lang.JoinPoint;
import org.aspectj.lang.annotation.AfterReturning;
import org.aspectj.lang.annotation.Aspect;
import org.aspectj.lang.annotation.Pointcut;
import org.aspectj.lang.reflect.MethodSignature;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.stereotype.Component;

import java.lang.reflect.Method;
import java.time.LocalDateTime;
import java.util.Arrays;

/**
 * @Author: ZhangDeZhong
 * @Date: 2024/12/12 09:24
 * @Description: 操作日志切面处理类
 **/
@Aspect
@Component
@RequiredArgsConstructor
public class SysLogAspect {

    private final HttpServletRequest request;

    private final SysOperationLogService sysOperationLogService;

    private static final Logger logger = LoggerFactory.getLogger(SysLogAspect.class);

    @Pointcut("@annotation(SysLog)")
    public void logPointcut() {
    }

    /**
     * 保存日志记录
     */
    @AfterReturning(pointcut = "logPointcut()")
    public void saveOperationLog(JoinPoint joinPoint) {
        // 获取方法签名
        MethodSignature signature = (MethodSignature) joinPoint.getSignature();
        Method method = signature.getMethod();

        // 获取 @SysLog 注解
        SysLog sysLog = method.getAnnotation(SysLog.class);

        // 创建日志对象
        SysOperationLog log = new SysOperationLog();
        log.setCreatedTime(LocalDateTime.now()); // 设置创建时间
        log.setCreateUser(getCurrentCreateUser());
        log.setContent(sysLog.value());
        log.setOperationType(sysLog.operationType());
        log.setModule(sysLog.module());
        log.setMethod(method.getName());
        log.setPath(request.getRequestURI());
        log.setParams(getRequestParams(joinPoint));
        log.setIpAddress(request.getRemoteAddr());
        log.setBrowser(getClientBrowser(request.getHeader("User-Agent")));
        log.setOs(getClientOS(request.getHeader("User-Agent")));

        // 保存日志记录到数据库
        sysOperationLogService.save(log);
        // 保存日志记录到日志文件中
        logger.info("操作日志 - 用户ID: {}, 内容: {}, 类型: {}, 模块: {}, 方法: {}, 请求路径: {}, 请求参数: {}, " +
                        "登录IP: {}, 国家: {}, 省: {}, 市: {}, 浏览器: {}, 操作系统: {}",
                log.getCreateUser(), log.getContent(), log.getOperationType(), log.getModule(),
                log.getMethod(), log.getPath(), log.getParams(), log.getIpAddress(),
                log.getCountry(), log.getProvince(), log.getCity(), log.getBrowser(), log.getOs());
    }

    /**
     * 获取请求参数
     */
    private String getRequestParams(JoinPoint joinPoint) {
        Object[] args = joinPoint.getArgs();
        String string = Arrays.toString(args);
        if (string.length() > 900) {
            return string.substring(0, 900) + "...";
        }
        return string;
    }

    /**
     * 获取浏览器参数
     */
    private String getClientBrowser(String userAgent) {
        if (userAgent.contains("Chrome") && !userAgent.contains("Edge")) {
            return "Chrome";
        } else if (userAgent.contains("Firefox")) {
            return "Firefox";
        } else if (userAgent.contains("Safari") && !userAgent.contains("Chrome")) {
            return "Safari";
        } else if (userAgent.contains("Edge")) {
            return "Edge";
        } else if (userAgent.contains("MSIE") || userAgent.contains("Trident")) {
            return "Internet Explorer";
        } else if (userAgent.contains("Opera") || userAgent.contains("OPR")) {
            return "Opera";
        }
        return "Other";
    }

    /**
     * 获取操作系统
     */
    private String getClientOS(String userAgent) {
        if (userAgent.contains("Windows")) return "Windows";
        if (userAgent.contains("Mac")) return "Mac";
        if (userAgent.contains("Linux")) return "Linux";
        return "Other";
    }

    /**
     * 获取当前登录用户ID
     */
    private String getCurrentCreateUser() {
        if (StpUtil.isLogin()) {
            return StpUtil.getSession().get("username").toString();
        }
        return null;
    }
}

